Įvaldykite „JavaScript“ pasirenkamąjį grandinimą, skirtą saugiai pasiekti giliai įdėtus objektus. Sužinokite praktinius pavyzdžius ir geriausią praktiką globalioms programoms.
JavaScript pasirenkamasis grandinimas giliame įdėjime: daugiapakopė saugi prieiga
Dinamiškame žiniatinklio kūrimo pasaulyje, ypač dirbant su sudėtingomis duomenų struktūromis ir API, saugus prieigavimas prie giliai įdėtų objekto savybių yra dažnas iššūkis. Tradiciniai metodai dažnai reikalauja daugybės patikrinimų, o tai lemia daug teksto ir klaidų. „JavaScript“ įdiegus pasirenkamąjį grandinimą (?.), buvo pakeista, kaip tvarkome tokius scenarijus, leidžiant sukurti glaustesnį ir patikimesnį kodą, ypač dirbant su daugiapakopiu įdėjimu. Šis įrašas nagrinės pasirenkamojo grandinimo subtilybes giliame įdėjime, pateikiant praktinius pavyzdžius ir veiksmingas įžvalgas pasaulinei kūrėjų auditorijai.
Problema: naršymas giliai įdėtuose duomenyse be klaidų
Įsivaizduokite, kad dirbate su duomenimis, gautais iš tarptautinės el. prekybos platformos. Šie duomenys gali būti struktūrizuoti taip:
const order = {
id: 'ORD12345',
customer: {
profile: {
name: 'Anya Sharma',
contact: {
email: 'anya.sharma@example.com',
phoneNumbers: [
{ type: 'mobile', number: '+91 98765 43210' },
{ type: 'work', number: '+91 11 2345 6789' }
]
}
},
preferences: {
language: 'en-IN'
}
},
items: [
{ productId: 'PROD001', quantity: 2, price: 50.00 },
{ productId: 'PROD002', quantity: 1, price: 120.50 }
],
shippingAddress: {
street: '123 Gandhi Road',
city: 'Mumbai',
country: 'India'
}
};
Dabar tarkime, kad norite gauti kliento mobiliojo telefono numerį. Be pasirenkamojo grandinimo, galite parašyti taip:
let mobileNumber;
if (order && order.customer && order.customer.profile && order.customer.profile.contact && order.customer.profile.contact.phoneNumbers) {
mobileNumber = order.customer.profile.contact.phoneNumbers.find(phone => phone.type === 'mobile')?.number;
}
console.log(mobileNumber); // Output: '+91 98765 43210'
Šis kodas veikia, bet yra per daug išsamus. Kas nutinka, jei trūksta bet kurios tarpinės savybės (pvz., contact arba phoneNumbers)? Kodas išmestų TypeError: "Negalima perskaityti neapibrėžtų savybių (skaitant '...')". Tai yra dažnas klaidų šaltinis, ypač dirbant su duomenimis iš įvairių šaltinių ar API, kurie ne visada gali grąžinti visą informaciją.
Pristatome pasirenkamąjį grandinimą (?.)
Pasirenkamasis grandinimas suteikia daug švaresnę sintaksę, skirtą pasiekti įdėtas savybes. Operatorius ?. sutrumpina įvertinimą, kai tik susiduria su null arba undefined reikšme, grąžindamas undefined vietoj klaidos išmetimo.
Pagrindinis naudojimas
Perrašykime ankstesnį pavyzdį naudojant pasirenkamąjį grandinimą:
const order = {
id: 'ORD12345',
customer: {
profile: {
name: 'Anya Sharma',
contact: {
email: 'anya.sharma@example.com',
phoneNumbers: [
{ type: 'mobile', number: '+91 98765 43210' },
{ type: 'work', number: '+91 11 2345 6789' }
]
}
},
preferences: {
language: 'en-IN'
}
},
items: [
{ productId: 'PROD001', quantity: 2, price: 50.00 },
{ productId: 'PROD002', quantity: 1, price: 120.50 }
],
shippingAddress: {
street: '123 Gandhi Road',
city: 'Mumbai',
country: 'India'
}
};
const mobileNumber = order?.customer?.profile?.contact?.phoneNumbers?.find(phone => phone.type === 'mobile')?.number;
console.log(mobileNumber); // Output: '+91 98765 43210'
Tai yra žymiai lengviau skaitoma. Jei bet kuri grandinės dalis (pvz., order.customer.profile.contact) yra null arba undefined, išraiška bus įvertinta kaip undefined be klaidų.
Tinkamas trūkstamų savybių valdymas
Apsvarstykite scenarijų, kai klientas gali neturėti nurodyto kontaktinio numerio:
const orderWithoutContact = {
id: 'ORD67890',
customer: {
profile: {
name: 'Kenji Tanaka'
// No contact information here
}
}
};
const mobileNumberForKenji = orderWithoutContact?.customer?.profile?.contact?.phoneNumbers?.find(phone => phone.type === 'mobile')?.number;
console.log(mobileNumberForKenji); // Output: undefined
Užuot sustabdęs veikimą, kodas gražiai grąžina undefined. Tai leidžia mums pateikti numatytąsias vertes arba tinkamai tvarkyti duomenų trūkumą.
Gilus įdėjimas: kelių pasirenkamųjų operatorių grandinimas
Pasirenkamojo grandinimo galia tikrai atsiskleidžia dirbant su keliais įdėjimo lygiais. Galite sujungti kelis ?. operatorius, kad saugiai naršytumėte sudėtingose duomenų struktūrose.
Pavyzdys: prieiga prie įdėtojo nustatymo
Pabandykime pasiekti kliento pageidaujamą kalbą, kuri yra įdėta keliais lygiais giliau:
const customerLanguage = order?.customer?.preferences?.language;
console.log(customerLanguage); // Output: 'en-IN'
Jei trūktų objekto preferences arba jame nebūtų savybės language, customerLanguage būtų undefined.
Masyvų tvarkymas įdėtose struktūrose
Dirbant su masyvais, kurie yra įdėtos struktūros dalis, galite derinti pasirenkamąjį grandinimą su masyvo metodais, tokiais kaip find, map, arba pasiekti elementus pagal indeksą.
Gaukime pirmojo telefono numerio tipą, darant prielaidą, kad jis egzistuoja:
const firstPhoneNumberType = order?.customer?.profile?.contact?.phoneNumbers?.[0]?.type;
console.log(firstPhoneNumberType); // Output: 'mobile'
Čia ?.[0] saugiai pasiekia pirmąjį phoneNumbers masyvo elementą. Jei phoneNumbers yra null, undefined arba tuščias masyvas, jis bus įvertintas kaip undefined.
Pasirenkamojo grandinimo derinimas su „Nullish Coalescing“ (??)
Pasirenkamasis grandinimas dažnai naudojamas kartu su „Nullish Coalescing“ operatoriumi (??), kad būtų pateiktos numatytosios reikšmės, kai savybė trūksta arba yra null/undefined.
Tarkime, kad norime gauti kliento el. pašto adresą, o jei jis nepasiekiamas, numatytasis nustatymas būtų "Nepateikta":
const customerEmail = order?.customer?.profile?.contact?.email ?? 'Not provided';
console.log(customerEmail); // Output: 'anya.sharma@example.com'
// Example with missing email:
const orderWithoutEmail = {
id: 'ORD11223',
customer: {
profile: {
name: 'Li Wei',
contact: {
// No email property
}
}
}
};
const liWeiEmail = orderWithoutEmail?.customer?.profile?.contact?.email ?? 'Not provided';
console.log(liWeiEmail); // Output: 'Not provided'
Operatorius ?? grąžina dešiniosios pusės operandą, kai kairiosios pusės operandas yra null arba undefined, o kitu atveju grąžina kairiosios pusės operandą. Tai yra nepaprastai naudinga nustatant numatytąsias reikšmes glaustu būdu.
Naudojimo atvejai globaliame kūrime
Pasirenkamasis grandinimas ir „nullish coalescing“ yra neįkainojami įrankiai kūrėjams, dirbantiems su globaliomis programomis:
-
Internacionalizuotos programos (i18n): Gauti lokalizuotą turinį ar vartotojo nuostatas, duomenų struktūros gali tapti giliai įdėtos. Pasirenkamasis grandinimas užtikrina, kad jei trūksta konkretaus kalbos ištekliaus ar nustatymo, programa nesustotų. Pavyzdžiui, prieiga prie vertimo gali atrodyti taip:
translations[locale]?.messages?.welcome ?? 'Welcome'. -
API integracijos: API iš skirtingų tiekėjų ar regionų gali turėti skirtingas atsakymų struktūras. Kai kurie laukai gali būti pasirenkami arba pateikiami sąlyginai. Pasirenkamasis grandinimas leidžia saugiai išgauti duomenis iš šių įvairių API be išsamaus klaidų tvarkymo.
Apsvarstykite vartotojo duomenų gavimą iš kelių paslaugų:
const userProfile = serviceA.getUser(userId)?.profile?.details ?? serviceB.getProfile(userId)?.data?.attributes; - Konfigūracijos failai: Sudėtingi konfigūracijos failai, ypač tie, kurie įkeliami dinamiškai arba iš nuotolinių šaltinių, gali pasinaudoti saugia prieiga. Jei konfigūracijos nustatymas yra giliai įdėtas ir gali ne visada būti, pasirenkamasis grandinimas apsaugo nuo vykdymo laiko klaidų.
- Trečiųjų šalių bibliotekos: Sąveikaujant su trečiųjų šalių „JavaScript“ bibliotekomis, jų vidinės duomenų struktūros gali ne visada būti visiškai dokumentuotos ar nuspėjamos. Pasirenkamasis grandinimas suteikia saugumo tinklą.
Kraštutiniai atvejai ir svarstymai
Pasirenkamasis grandinimas vs. loginis IR (&&)
Prieš pasirenkamąjį grandinimą kūrėjai dažnai naudojo loginį IR operatorių patikrinimams:
const userEmail = order && order.customer && order.customer.profile && order.customer.profile.contact && order.customer.profile.contact.email;
Nors tai veikia, yra esminis skirtumas: operatorius && grąžina paskutinio teisingo operando arba pirmo klaidingo operando reikšmę. Tai reiškia, kad jei order.customer.profile.contact.email būtų tuščia eilutė (''), kuri yra klaidinga, visa išraiška būtų įvertinta kaip ''. Pasirenkamasis grandinimas, kita vertus, konkrečiai tikrina, ar nėra null arba undefined. „Nullish coalescing“ operatorius (??) yra modernus, pageidaujamas būdas tvarkyti numatytąsias reikšmes, nes jis suveikia tik esant null arba undefined.
Pasirenkamasis grandinimas funkcijoms
Pasirenkamasis grandinimas taip pat gali būti naudojamas sąlyginiam funkcijų iškvietimui:
const userSettings = {
theme: 'dark',
updatePreferences: function(prefs) { console.log('Updating preferences:', prefs); }
};
// Safely call updatePreferences if it exists
userSettings?.updatePreferences?.({ theme: 'light' });
const noUpdateSettings = {};
noUpdateSettings?.updatePreferences?.({ theme: 'dark' }); // Does nothing, no error
Čia userSettings?.updatePreferences?.() pirmiausia patikrina, ar updatePreferences egzistuoja objekte userSettings, o tada patikrina, ar rezultatas yra funkcija, kurią galima iškviesti. Tai naudinga pasirenkamiems metodams arba atgalinio ryšio funkcijoms.
Pasirenkamasis grandinimas ir operatorius `delete`
Pasirenkamasis grandinimas nesąveikauja su operatoriumi delete. Negalite naudoti ?., kad sąlyginai ištrintumėte savybę.
Poveikis našumui
Labai kritiškiems našumo atžvilgiu ciklais arba labai gilioms, nuspėjamoms struktūroms, perteklinis pasirenkamasis grandinimas galėtų šiek tiek padidinti sąnaudas. Tačiau daugeliu atvejų kodo aiškumo, palaikomumo ir klaidų prevencijos privalumai gerokai nusveria bet kokį minimalų našumo skirtumą. Šiuolaikinės „JavaScript“ varikliai yra labai optimizuoti šiems operatoriams.
Geriausia praktika giliam įdėjimui
-
Nuosekliai naudokite
?.: Kiekvieną kartą, kai pasiekiate potencialiai trūkstamą įdėtą savybę, naudokite pasirenkamojo grandinimo operatorių. -
Derinkite su
??numatytosioms reikšmėms: Naudokite „nullish coalescing“ operatorių (??), kad pateiktumėte protingas numatytąsias reikšmes, kai savybė yranullarbaundefined. - Venkite pernelyg didelio grandinimo, kai nereikia: Jei esate visiškai tikri, kad savybė egzistuoja (pvz., primityvi savybė giliai įdėtame objekte, kurį patys sukūrėte su griežtu patvirtinimu), galite atsisakyti pasirenkamojo grandinimo dėl nedidelio našumo padidėjimo, tačiau tai daryti reikia atsargiai.
- Skaitomumas, o ne neaiškumas: Nors pasirenkamasis grandinimas padaro kodą glaustą, venkite grandinimo taip giliai, kad taptų sunku suprasti. Ypač sudėtingiems scenarijams apsvarstykite dekonstravimą arba pagalbines funkcijas.
- Kruopščiai išbandykite: Įsitikinkite, kad jūsų pasirenkamojo grandinimo logika apima visus numatomus trūkstamų duomenų atvejus, ypač integruojant su išorinėmis sistemomis.
- Apsvarstykite „TypeScript“: Didelio masto programoms „TypeScript“ siūlo statinį tipavimą, kuris gali aptikti daugelį šių potencialių klaidų kūrimo metu, papildydamas „JavaScript“ vykdymo laiko saugumo funkcijas.
Išvada
„JavaScript“ pasirenkamasis grandinimas (?.) ir „nullish coalescing“ (??) yra galingos modernios funkcijos, kurios žymiai pagerina tai, kaip tvarkome įdėtas duomenų struktūras. Jos suteikia tvirtą, lengvai skaitomą ir saugų būdą pasiekti potencialiai trūkstamas savybes, drastiškai sumažinant vykdymo laiko klaidų tikimybę. Įvaldę gilų įdėjimą su šiais operatoriais, kūrėjai visame pasaulyje gali kurti atsparesnes ir lengviau prižiūrimas programas, nesvarbu, ar jie dirba su globaliomis API, internacionalizuotu turiniu, ar sudėtingais vidiniais duomenų modeliais. Pasinaudokite šiomis priemonėmis, kad rašytumėte švaresnį, saugesnį ir profesionalesnį „JavaScript“ kodą.